//
// Created by Chiro on 2022/2/22.
//

#ifndef CHISEL_X_MODEL_H
#define CHISEL_X_MODEL_H

#include <common.h>
#include <utils.h>
#include <typeinfo>
#include <cstdio>
#include <memory>
#include <cstdlib>
#include <debug.h>

#define IS_DIFF(x) DIFFTEST_##x

#ifdef USE_MODEL
#ifndef MODEL_ONLY

#include <verilated.h>

#endif

#endif

class VerilatedFake {
public:
  static bool begin, finish;

  static bool gotFinish();

  static void traceEverOn(bool enable);

  uint8_t clock, reset;

  virtual void eval() = 0;

  static void final();

  VerilatedFake();
};

template<typename T>
class VerilatedDiff : public VerilatedFake {
public:
  std::shared_ptr<T> dut = nullptr;

  VerilatedDiff() {
    dut = std::make_shared<T>();
    // 用反射机制得到当前 Difftest 的模块名称（C++的话不是类名）
    // Log("Verilator Diff " ASNI_FMT("ON", ASNI_FG_RED ASNI_BG_YELLOW) " for %s", typeid(*dut).name());
    Log("Verilator Diff " "ON" " for %s", typeid(*dut).name());
  }

  ~VerilatedDiff() { dut->final(); }

  // Interfaces
  // 从 DUT 加载
  virtual void dut_load() = 0;

  // 应用到 DUT
  virtual void dut_apply() = 0;

  // 差分测试
  virtual bool dut_check() = 0;
};

#endif //CHISEL_X_MODEL_H
